#include <iostream>
#include <string>
#include <pthread.h>
#include <thread>
#include <unistd.h>
#include <cassert>

using namespace std;

// 抢票程序
// 总共的票数
int tickets = 10000;

#define THREAD_NUM 800 // 创建了 THREAD_NUM 个线程，每个线程代表一个抢票者。

class ThreadData
{
public:
    ThreadData(const string &n, pthread_mutex_t* pm)
        :tname(n)
        ,pmtx(pm)
    {}

public:
    // 成员变量
    string tname;
    pthread_mutex_t* pmtx; //设置锁
};

// 每个线程运行 getTickets() 函数，通过互斥锁来保护 tickets 变量的访问和修改。
void* getTickets(void* args)
{
    ThreadData* td = (ThreadData*)args;
    while(true)
    {
        // 抢票逻辑
        int n = pthread_mutex_lock(td->pmtx); // 上锁
        assert(n == 0);
        // 临界区
        // 在临界区内，每个线程判断是否还有票可供抢购，如果有，则随机休眠一段时间（模拟抢票过程），然后打印当前线程名以及剩余票数，并将票数减一，最后释放互斥锁。 
        if(tickets > 0)
        {
            usleep(rand() % 1500);
            cout << td->tname.c_str() << " : " << tickets << endl;
            --tickets;
            n = pthread_mutex_unlock(td->pmtx);
            assert(n == 0);
        }
        // 如果没有票可供抢购，则直接释放互斥锁并退出循环。
        else{
            n = pthread_mutex_unlock(td->pmtx);
            assert(n == 0);
            break;
        }

        // 在抢完票后，每个线程再次随机休眠一段时间，模拟后续动作。
        usleep(rand() % 2000);
    }
    // 主线程等待所有子线程执行完毕，销毁互斥锁。
    delete td;
    return nullptr;
}

int main()
{
    time_t start = time(nullptr);
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, nullptr);

    srand((unsigned long)time(nullptr) ^ getpid() ^ 0x147);
    pthread_t t[THREAD_NUM]; // 线程

    // 多线程抢票的逻辑
    // 分别打印各个线程的情况
    for(int i = 0; i < THREAD_NUM; ++i){
        string name = "thread ";
        name += to_string(i + 1);
        ThreadData* td = new ThreadData(name, &mtx);
        pthread_create(t+i, nullptr, getTickets, (void*)td);
    }

    // 等待线程结束
    for(int i = 0; i < THREAD_NUM; ++i){
        pthread_join(t[i], nullptr);
    }

    // 销毁锁
    pthread_mutex_destroy(&mtx);
    
    time_t end = time(nullptr);

    cout << "cast: " << (int)(end-start) << "S" << endl;

    return 0;
}
